package NodeInfo;
import java.util.Random;
import java.util.Vector;

import com.sun.corba.se.impl.orbutil.closure.Future;

import Emulator.Emulator;
import Emulator.RangePair;

public class NodeThread extends Thread{

	public NodeInfo nodeinfo;
	public Random rand;
	public int ladoGrid=10000;

	public void run() {
		while(true){
			nodeinfo.setCountSteps(nodeinfo.getCountSteps()+1);
			Vector<RangePair> neighbors=Emulator.whoAreMyNeighbors(nodeinfo.getNodeId());
			if(nodeinfo.getAmISlave()==nodeinfo.getNodeId() && neighbors.isEmpty()){
				if(nodeinfo.getLevel()==1){ //level1
					if(nodeinfo.getFutureMoves().isEmpty()){
						nodeinfo.getFutureMoves().push(90);//270+180
						nodeinfo.getFutureMoves().push(270);
						nodeinfo.getFutureMoves().push(0);//180+180
						nodeinfo.getFutureMoves().push(180);
						nodeinfo.getFutureMoves().push(90+180);
						nodeinfo.getFutureMoves().push(90);
						nodeinfo.getFutureMoves().push(180);
						nodeinfo.getFutureMoves().push(0);

						move(nodeinfo.getFutureMoves().pop());
					}else{
						move(nodeinfo.getFutureMoves().pop());
						if(nodeinfo.getFutureMoves().isEmpty())
							nodeinfo.setLevel(2);
					}
				}else{
					if(nodeinfo.getLevel()==2){
						if(nodeinfo.getFutureMoves().isEmpty()){
							nodeinfo.getFutureMoves().push(nodeinfo.getAxis()+180);
							nodeinfo.getFutureMoves().push(nodeinfo.getAxis()+45+180);
							nodeinfo.getFutureMoves().push(nodeinfo.getAxis()+45);
							nodeinfo.getFutureMoves().push(nodeinfo.getAxis()-45+180);
							nodeinfo.getFutureMoves().push(nodeinfo.getAxis()-45);
							nodeinfo.getFutureMoves().push(nodeinfo.getAxis());
							nodeinfo.setAxis(nodeinfo.getAxis()+90);

							move(nodeinfo.getFutureMoves().pop());
						}else{
							move(nodeinfo.getFutureMoves().pop());
							if(nodeinfo.getFutureMoves().isEmpty() && nodeinfo.getAxis()==360)
								nodeinfo.setLevel(3);
						}
					}else{
						if(nodeinfo.getCountRdm()>0){
							move(rand.nextInt(360));
							nodeinfo.setCountRdm(nodeinfo.getCountRdm()-1);
						}else{
							nodeinfo.setLevel(1);
							nodeinfo.setCountRdm(20);
							nodeinfo.getFutureMoves().clear();
						}
					}
				}
			}else{
				if(!neighbors.isEmpty() ){
						int menor=nodeinfo.getAmISlave();
						for(RangePair ra:neighbors){
							int i=ra.getA().getNodeId();
							if(i<menor)
								menor=i;
						}
						String msg="s"+menor;
						for(RangePair p:neighbors){
							Emulator.SendMsg(msg, nodeinfo.getNodeId(), p.getA().getNodeId());
						}
						if(menor!=nodeinfo.getNodeId() && nodeinfo.isCanIChangeStatus()){
							nodeinfo.setAmISlave(menor);
							nodeinfo.setCanIChangeStatus(false);
						}else{
							if(menor==nodeinfo.getNodeId()){
								//memorize this position
								goWalk();
							}
						}
						
						for(String rec: nodeinfo.getReceivedMsgs()){
							if(rec.startsWith("s")){
								int masterID=Integer.valueOf(rec.substring(1));
								if(masterID<menor)
									menor=masterID;
							}
						}
				}
			}
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

	private void goWalk() {
		if(nodeinfo.getCountRdm()>0){
			int tmp=rand.nextInt(360);
			move(tmp);
			nodeinfo.getMoves().push(tmp);
			nodeinfo.setCountRdm(nodeinfo.getCountRdm()-1);
		}
	}

	public NodeThread (int nodeId){
		rand=new Random();

		nodeinfo=new NodeInfo();
		nodeinfo.setNodeId(nodeId);

		nodeinfo.setXpos(rand.nextInt(ladoGrid)); 
		nodeinfo.setYpos(rand.nextInt(ladoGrid));
	}

	public void move(int angle){
		float rad=(float)(angle*Math.PI)/180;
		nodeinfo.setXpos((float)(Math.cos(rad)*nodeinfo.getSpeed()));
		nodeinfo.setYpos((float)(Math.sin(rad)*nodeinfo.getSpeed()));

		if(nodeinfo.getXpos()>ladoGrid)
			nodeinfo.setXpos((float) (Math.random()*ladoGrid));
		if(nodeinfo.getYpos()>ladoGrid)
			nodeinfo.setYpos((float) (Math.random()*ladoGrid));
		/*	final Object lock=this;
			synchronized(lock)
			{
				try {
					lock.wait();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}*/
	}

	public NodeInfo getNodeinfo() {
		return nodeinfo;
	}

	public void setNodeinfo(NodeInfo nodeinfo) {
		this.nodeinfo = nodeinfo;
	}
}